module arm.misc;
/**
* 位运算参考 $(Link https://www.codenong.com/47981/)
*/

import std.traits ;
import std.meta : allSatisfy;

//import arm.c.misc_bits;

//pragma(msg,"8:",ByteField.sizeof);
//pragma(msg,"16:",UshortField.sizeof);
//pragma(msg,"32:",UintField.sizeof);





/**
* 调试模式下禁用内联,提高调试效率
* Example:
---
pragma(inline,_inline)
---
*/
debug{
    enum bool _inline = false;
}else{
    enum bool _inline = true;
}





// 内存映射结构表

/// 根据位长度返回可用类型
template SelectType4Unsigned( size_t n) if(n == 1)
{
    alias SelectType4Unsigned = bool;
}
template SelectType4Unsigned( size_t n) if(n > 1) 
{
    //pragma(msg,"SelectType4Unsigned:",n);
    static if(n <= 8){
		alias SelectType4Unsigned = ubyte;
	}else static if(n <= 16){
		alias SelectType4Unsigned = ushort;
	}else static if(n <= 32){
		alias SelectType4Unsigned = uint;
	}else{
		static assert(false," > 32");
	}
}

unittest
{
    assert(is(SelectType4Unsigned!() == bool) );
    assert(is(SelectType4Unsigned!(2) == ubyte) );
    assert(is(SelectType4Unsigned!(7) == ubyte) );
    assert(is(SelectType4Unsigned!(8) == ubyte) );
    assert(is(SelectType4Unsigned!(16) == ushort) );
    assert(is(SelectType4Unsigned!(32) == uint) );
    assert(is(SelectType4Unsigned!(64) == ulong) );
    
}

/**
* 查找枚举值对应的名字
*/



/**
    按位设置掩码位

    example:
    
    MakerMask4Slice!(起始位,截至位);
    
    note:
    返回类型为宽度匹配的无符号整数类型
    返回值为匹配位的掩码
*/

/*
template MakerMask4Slice(size_t _start,size_t _end) //if(_start < _end)
{
    //pragma(msg,"start:",_start,"\tend:",_end);
    private enum _size = _end - _start;

    private alias mType = SelectType4Unsigned!(_size);

    //pragma(msg,"((",mType.max," >> ((",mType.sizeof*8,") - (",_size,"))) << ",_start,");");

    enum MakerMask4Slice = (
        (mType.max >> ((mType.sizeof*8) - (_size))) << _start
        );
}

*/
T MakerMask(T = uint)(size_t l,size_t h) pure nothrow @safe
in(l<h)
in(h <= T.sizeof*8)
{
    return (T.max >> (T.sizeof*8 - (h-l))) << l;
}

/// 生成数据切片掩码 32位
///Examples: MakerMask!(0,1) == 0b0001
template MakerMask( size_t _start,size_t _end) if((_start < _end) && (_end <= 32) && (_start < 32))
{
    private enum size_t _loffset = (uint.sizeof*8) - (_end - _start);
    private enum size_t _roffset = _start;

    enum MakerMask = (uint.max >> _loffset) << (_roffset);
}

unittest
{
    assert(MakerMask!(0,1) == 0b0001);
    assert(MakerMask!(0,2) == 0b0011);
    assert(MakerMask!(5,6) == 0b10_0000);
}

/**
    按位置构建bit的mask
    ----
    auto mask = combineMasks!(0,1);
    ----
*/
template combineMasks(T...) if (allSatisfy!(isNumeric, typeof(T)) )
{
	static if(T.length >= 2){
		enum combineMasks = (1u << T[0] ) | combineMasks!(T[1..$]);
	}else static if(T.length == 1){
		enum combineMasks = (1u << T[0] );
	}else{
		enum combineMasks = 0;
	}
}

unittest
{
    assert(combineMasks!() == 0);
    assert(combineMasks!(0) == 1);
    assert(combineMasks!(1) == 2);
    assert(combineMasks!(2) == 4);
    assert(combineMasks!(3) == 8);
    assert(combineMasks!(0,1,2,3) == 0x0f);
}

/*
    返回最大值
*/
template maxNumber(T...) if(allSatisfy!(isNumeric, typeof(T)))
{
    static if (T.length == 0){
        static assert(0);
    }else static if (T.length == 1){
        enum maxNumber = T[0];
    }else static if (T.length == 2){
        enum maxNumber = T[0] > T[1] ? T[0] : T[1];
    }else{
        enum a = maxNumber!(T[0 .. ($+1)/2]);
        enum b = maxNumber!(T[($+1)/2 .. $]);
        enum maxNumber = a > b ? a : b;
    }
}

unittest
{
    assert(maxNumber!(5) == 5);
    assert(maxNumber!(1,3,5,2,4,8) == 8);
    assert(maxNumber!(5,4,3,2,1) == 5);
    assert(maxNumber!(5,5,6) == 6);
}

/**
    指定内存位置写入数据 $(D addr) 必须是常量
    Params: 
        addr = 内存地址
        val = 数据
    Examples: 
    ---
    WriteMemory!(0x2000_0000)(0x1234_5678);
    ---
*/
pragma(inline,_inline)
void WriteMemory(size_t addr,T)(T val) if(is(T == ubyte) || is(T == ushort) || is(T == uint) || is(T == ulong))
{
    import core.volatile;
    volatileStore(cast(T*)addr,val);
}

/**
指定内存位置读取数据  $(D addr) 必须是常量
Params: 
    addr = 内存地址
Examples: 
---
auto val = ReadMemory!(0x2000_0000,uint)();
---
*/
deprecated
pragma(inline,_inline)
T ReadMemory(size_t addr,T)() if(is(T == ubyte) || is(T == ushort) || is(T == uint) || is(T == ulong))
{
    import core.volatile;
    return volatileLoad(cast(T*)addr);
}


/**
* 中断服务混入模板
*/
mixin template MakerIRQHandler(alias funcname,alias callFn)
{
    //pragma(mangle,funcname.mangleof)
    //funcname.stringof
    // void 
    enum string MakerIRQHandler = "pragma(mangle,"~funcname.mangleof~") void c_"  ~ funcname.stringof ~
        " {if(" ~ callFn.stringof ~ " !is null) " ~ callFn.stringof ~ "();}";

    //mixin(MakerIRQHandler);
    
    //mixin(q{pragma(mangle,WWDG_IRQHandler.mangleof) extern(C) void c_WWDG_IRQHandler() {if(m_Callhandler !is null) m_Callhandler();}});

    //pragma(msg,funcname.mangleof);
    pragma(msg,"cc:",MakerIRQHandler);
}

/**
* 内存映射地址,返回一个内存指针,用于访问外设
* 不做任何地址检查
* Examples:
* ---
* enum RegMap = RegMap!(0x4002_1000,ushort);
* ---
*/
template RegMap( size_t paddr,T) //if(!isPointer!T)
{
    enum RegMap = cast(T*)paddr;
}

/**
* 转换到小写
*/
template ToLower(string v)
{
    import std.ascii : toLower;
    static if(v.length == 0){
        enum ToLower = "";
    }else{
        enum ToLower = ToLower!(v[0..v.length-1]) ~ v[v.length-1].toLower;
    }
}
/**
* 转换到大写
*/
template ToUpper(string v)
{
    import std.ascii : toUpper;
    import std.complex;
    static if(v.length == 0){
        enum ToUpper = "";
    }else{
        enum ToUpper = ToUpper!(v[0..v.length-1]) ~ v[v.length-1].toUpper;
    }
}

/**
*    比较两个字符串是否相等,忽略大小写
*/
template CmpVal(string v1,string v2)
{
    static if(v1.length != v2.length){
        enum CmpVal = false;
    }else{
        enum CmpVal = (ToLower!v1 == ToLower!v2);
    };
}





/**
* 寄存器操作 使用 core.volatile 方式读写
*/
pragma(inline,_inline)
package{
    import std.traits ;
    import core.atomic : atomicOp;
    import core.volatile : volatileLoad,volatileStore;
    import core.bitop;
    
    /**
    * 判定指定寄存器的位 模板方式
    * Params:
    *   mAddress = 寄存器地址
    *   mPos = 位置
    * Todo: 未考虑位带区操作
    */
    static bool hasBit(size_t mAddress,size_t mPos,T = uint)() if(isUnsigned!T)
    in(T.sizeof*8 > mPos)
    {
        return hasBit!(cast(T*)mAddress,mPos,T);
    }
    static bool hasBit(alias p,size_t mPos)() if( 
        is(PointerTarget!p == ubyte) ||
        is(PointerTarget!p == ushort) ||
        is(PointerTarget!p == uint) ||
        is(PointerTarget!p == ulong)
    )
    in((PointerTarget!p).sizeof*8 > mPos)
    {
        return (volatileLoad(p) & (1u << mPos)) != 0;
    }
    /// 设置位
    static void setBit(size_t mAddress,size_t mPos,T = uint)()
    in(T.sizeof*8 > mPos)
    {        
        enum p = RegMap!(mAddress,uint);
        atomicOp!"|="(*cast(shared(uint)*)p, (1u << mPos));
    }
    static void setBit(alias p,size_t mPos)() if( 
        is(PointerTarget!p == ubyte) ||
        is(PointerTarget!p == ushort) ||
        is(PointerTarget!p == uint) ||
        is(PointerTarget!p == ulong)
    )
    in((PointerTarget!p).sizeof*8 > mPos)
    {
        atomicOp!"|="(*cast(shared(PointerTarget!p)*)p, (1u << mPos));
    }
    /// 清除位
    static clearBit(size_t mAddress,size_t mPos,T = uint)()
    in(T.sizeof*8 > mPos)
    {
        enum p = RegMap!(mAddress,uint);
        atomicOp!"&="(*cast(shared(uint)*)p, ~(1u << mPos));
    }
    


    /**
    * 读取指定寄存器的位 模板方式
    * Params:
    *   mAddress = 寄存器地址
    *   Mask = 位域掩码
    *   T = 寄存器类型
    * Todo: 考虑 xor 方式操作 cas
    */
    deprecated
    void modifyReg(size_t mask,T)(ref T reg,T val) => modifyReg!mask(cast(shared)reg,val);
    deprecated
    void modifyReg(size_t mask,T)(ref shared T reg,T val)
    {
        //auto preg = cast(shared)reg;
        enum pos = bsf(mask);                       /// 位域起始位置
        auto nval = (val << pos)&mask;              /// 获取有效位域值
        atomicOp!"&="(reg,~mask);                   /// 清除位域
        atomicOp!"|="(reg,val);                     /// 设置位域
    };
    deprecated
    void setBit(ref uint p,size_t mPos) => setBit(cast(shared)p,mPos);
    deprecated
    void setBit(ref shared uint p,size_t mPos)
    {
        atomicOp!"|="(p, (1u << mPos));
    }
    deprecated
    void clearBit(ref uint p,size_t mPos) => clearBit(cast(shared)p,mPos);
    deprecated
    void clearBit(ref shared uint p,size_t mPos)
    {
        atomicOp!"&="(p, ~(1u << mPos));
    }

    bool hasBit(ref uint p,size_t mPos)
    {
        return (volatileLoad(&p) & (1u<<mPos)) != 0;
    }
    /**
    * 按位域掩码读写位域,值按掩码右侧位对齐到0位
    */
    deprecated
    @property
    T BitField(size_t mask,T)(ref T reg) if(bsf(mask) != bsr(mask))
    {
        enum pos = bsf(mask);                       /// 位域起始位置
        return ((volatileLoad(&reg) & mask) >> pos);/// 获取有效位域值
    }
    deprecated
    @property
    T BitField(size_t mask,T)(ref T reg) if(bsf(mask) == bsr(mask))
    {
        // 应实现 位带区操作
        enum pos = bsf(mask);                       /// 位域起始位置
        return (volatileLoad(&reg) & mask) >> pos;  /// 获取有效位域值
    }
    deprecated
    @property BitField(size_t mask,T)(ref T reg,T val) => BitField!mask(cast(shared)reg,val);
    deprecated
    @property
    void BitField(size_t mask,T)(ref shared T reg,T val) if(bsf(mask) != bsr(mask))
    {
        enum pos = bsf(mask);                       /// 位域起始位置
        auto nval = (val << pos)&mask;              /// 获取有效位域值
        atomicOp!"&="(reg,~mask);                   /// 清除位域
        atomicOp!"|="(reg,val);                     /// 设置位域
    }
    deprecated
    @property
    void BitField(size_t mask,T)(ref shared T reg,T val) if(bsf(mask) == bsr(mask))
    {
        // 应实现 位带区操作
        enum pos = bsf(mask);                       /// 位域起始位置
        auto nval = (val << pos)&mask;              /// 获取有效位域值
        atomicOp!"&="(reg,~mask);                   /// 清除位域
        atomicOp!"|="(reg,val);                     /// 设置位域
    }
    deprecated
    void BitField_Clear(size_t mask,T)(ref T reg) if(bsf(mask) != bsr(mask))
    {
        atomicOp!"&="(reg,~mask);                   /// 清除位域
    }
    deprecated
    void BitField_Clear(size_t mask,T)(ref T reg) if(bsf(mask) == bsr(mask))
    {
        // 应实现 位带区操作
        atomicOp!"&="(reg,~mask);                   /// 清除位域
    }


    /**
    * 读取指定寄存器的位掩码 模板方式
    * Params:
    *   peri = 枚举类型
    *   m = 枚举常量名,可接受多个字符串参数,用于组合成一个常量名
    */
    template ReadMask(alias peri,string m) if(__traits(hasMember,peri,m) == true)
    {
        enum ReadMask = __traits(getMember,peri,m);
    }
    template ReadMask(alias peri,string m) if(__traits(hasMember,peri,m) == false)
    {
        static assert(false,"ReadMask: "~__traits(identifier,peri)~" has no member " ~ m);
        enum ReadMask = 0;
    }
    template ReadMask(alias peri,args...)
    {
        enum ReadMask = ReadMask!(peri,combineStr!(args));
    }
    /**
    *  转换 string[] 为 string
    */
    template combineStr(T...) if (allSatisfy!(isSomeString, typeof(T)) )
    {
        static if(T.length >= 2){
            enum combineStr = T[0] ~ combineStr!(T[1..$]);
        }else{
            enum combineStr = T[0];
        }
    }


}




